#include "timestamp.h"

#include "dbg_trace.h"

extern RTC_HandleTypeDef hrtc;


#define SECONDS_IN_MINUTE 60
#define SECONDS_IN_HOUR 3600
#define SECONDS_IN_DAY 86400
#define DAYS_IN_YEAR 365
#define DAYS_IN_LEAP_YEAR 366



static uint32_t ReadRtcSsrValue(void)
{
  uint32_t first_read;
  uint32_t second_read;

  first_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS));

  second_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS));

  while(first_read != second_read)
  {
    first_read = second_read;

    second_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS));
  }

  return second_read;
}

// 判断是否为闰年
static int is_leap_year(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

// 每个月的天数
static int days_in_month(int month, int year) {
    static const int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    if (month == 2 && is_leap_year(year)) {
        return 29;
    }
    return days[month - 1]; // month 从 1 开始
}

// 计算从1970年1月1日到给定日期的秒数
static time_t calculate_seconds(RTC_DateTypeDef *date, RTC_TimeTypeDef *time) {
    const int seconds_per_minute = 60;
    const int seconds_per_hour = 3600;
    const int seconds_per_day = 86400;
    
    int year = date->Year + 2000; // 假设RTC年份是从2000年开始计数的
    int month = date->Month;
    int day = date->Date;
    int hour = time->Hours;
    int minute = time->Minutes;
    int second = time->Seconds;
    
    // 计算从1970年到目标年份的总天数
    int days = 0;
    for (int y = 1970; y < year; y++) {
        days += is_leap_year(y) ? 366 : 365;
    }
    
    // 计算目标年份到目标月份的总天数
    for (int m = 1; m < month; m++) {
        days += days_in_month(m, year);
    }
    
    // 加上目标月份的天数
    days += (day - 1);
    
    // 计算总秒数
    time_t total_seconds = (time_t)days * seconds_per_day +
                           (time_t)hour * seconds_per_hour +
                           (time_t)minute * seconds_per_minute +
                           (time_t)second;
    
    return total_seconds;
}



uint64_t RTC_GetTimestampMillis(void)
{
	uint64_t ret_ms = 0;
	
	RTC_DateTypeDef sdatestructureget;
	RTC_TimeTypeDef stimestructureget;

	/* Get the RTC current Time */
	HAL_RTC_GetTime(&hrtc, &stimestructureget, RTC_FORMAT_BIN);
	/* Get the RTC current Date */
	HAL_RTC_GetDate(&hrtc, &sdatestructureget, RTC_FORMAT_BIN);
	
	time_t sec = calculate_seconds(&sdatestructureget, &stimestructureget);
	//APP_DBG_MSG("sec:%d \r\n", sec);
//	static uint32_t sec_cur = 0;
//	if(sec > sec_cur){
//	  sec_cur = sec;
//		APP_DBG_MSG("sec:%d \r\n", sec);
//	}

	uint32_t sub_ms = ((LSE_VALUE - ReadRtcSsrValue())*1000) / LSE_VALUE;
	ret_ms = sec *1000;
	ret_ms += sub_ms;
	
	return ret_ms;
}


static struct tm *my_localtime(const time_t *timer) {
    static struct tm local_time;
    time_t t = *timer;
    int year = 1970;

    // 计算年份
    while (t >= (is_leap_year(year) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR) * SECONDS_IN_DAY) {
        t -= (is_leap_year(year) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR) * SECONDS_IN_DAY;
        year++;
    }

    // 计算月份
    int month = 1;
    while (t >= days_in_month(month, year) * SECONDS_IN_DAY) {
        t -= days_in_month(month, year) * SECONDS_IN_DAY;
        month++;
    }

    // 计算日期
    int day = t / SECONDS_IN_DAY + 1;
    t %= SECONDS_IN_DAY;

    // 计算小时、分钟和秒
    int hour = t / SECONDS_IN_HOUR;
    t %= SECONDS_IN_HOUR;
    int minute = t / SECONDS_IN_MINUTE;
    int second = t % SECONDS_IN_MINUTE;

    // 填充 tm 结构
    local_time.tm_year = year - 1900;
    local_time.tm_mon = month - 1;
    local_time.tm_mday = day;
    local_time.tm_hour = hour;
    local_time.tm_min = minute;
    local_time.tm_sec = second;
    local_time.tm_isdst = -1;

    return &local_time;
}



uint8_t RTC_SetTimestamp(uint32_t timestamp)
{
	struct tm *plocalTime;
	plocalTime = my_localtime((time_t const*)&timestamp);
	RTC_DateTypeDef sdatestructureget = {0};
	RTC_TimeTypeDef stimestructureget = {0};
	
	if(plocalTime->tm_year + 1900 < 2000)
		return -1;
	
	sdatestructureget.Year = plocalTime->tm_year + 1900 - 2000;
	sdatestructureget.Month = plocalTime->tm_mon+1;
	sdatestructureget.Date = plocalTime->tm_mday;
	stimestructureget.Hours = plocalTime->tm_hour;
	stimestructureget.Minutes = plocalTime->tm_min;
	stimestructureget.Seconds = plocalTime->tm_sec;
	
	HAL_RTC_SetTime(&hrtc, &stimestructureget, RTC_FORMAT_BIN);
	HAL_RTC_SetDate(&hrtc, &sdatestructureget, RTC_FORMAT_BIN);
	
	return 0;
}














